package light.head.framework.utils;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import jxl.Workbook;
import jxl.format.Alignment;
import jxl.format.Border;
import jxl.format.BorderLineStyle;
import jxl.format.Colour;
import jxl.format.VerticalAlignment;
import jxl.write.Label;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import light.head.framework.entity.ExcelField;
import light.head.framework.entity.ExcelFieldComparator;

/**
 * @author janhang
 * @2012-5-21 下午08:46:14
 */
public class ExcelUtils {
	
	private final static String FIELD_LIST = "java.util.List";
	private final static String FIELD_STRING = "java.lang.String";
	/**
	 * 生成Excel
	 * @param models			封装需要到处的数据BEAN结合
	 * @param className			导成Excel的实体BEAN包名.类名
	 * @param tempPath			生成Excel存放的临时路径
	 * @param excelName			生成的Excel名
	 * @param listTitle			对象中没有出现的字段，并且要在标题中显示的。用于处理对象中的list属性
	 * @param listTitleWidth	listTitle对应的宽度
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void writeExcel(List rows, String sheetName, OutputStream os, List<String> listTitle, List<Integer> listTitleWidth) {
		Class clasVo = null;
		try {
			if (null == rows || rows.size() == 0) {
				os.flush();
				os.close();
				return;
			}
			String className = rows.get(0).getClass().getName();
			
			clasVo = Class.forName(className);
			WritableWorkbook workbook = Workbook.createWorkbook(os);
			WritableSheet sheet = workbook.createSheet(sheetName, 0);

			// 用于标题
			WritableFont fnFont = new WritableFont(WritableFont.createFont("宋体"), 9, WritableFont.BOLD);
			WritableCellFormat wcf_title = new WritableCellFormat(fnFont);
			wcf_title.setBorder(Border.ALL, BorderLineStyle.THIN, Colour.BLACK);
			wcf_title.setVerticalAlignment(VerticalAlignment.CENTRE);				// 垂直对齐
			wcf_title.setAlignment(Alignment.CENTRE);
			wcf_title.setWrap(true);												// 是否换行

			// 用于正文
			WritableFont fFont = new WritableFont(WritableFont.createFont("宋体"), 9);
			WritableCellFormat wcf_center = new WritableCellFormat(fFont);
			wcf_center.setBorder(Border.ALL, BorderLineStyle.THIN, Colour.BLACK);
			wcf_center.setVerticalAlignment(VerticalAlignment.CENTRE);				// 垂直对齐
			wcf_center.setAlignment(Alignment.LEFT);
			wcf_center.setWrap(true);												// 是否换行


			// 获取属性
			Field[] fields = clasVo.getDeclaredFields();
			List<Field> fs = new ArrayList<Field>();
			Object listF = null;
			// 获取含有excel注解的属性
			for (Field f : fields) {
				if (f.getAnnotation(ExcelField.class) != null) {
					// 如果该属性是List类型，就需要特殊处理，并且一个对象只能有一个list，多个将不能处理
					if (FIELD_LIST.equals(f.getType().getName())) {
						listF = f;
					} else {
						fs.add(f);
					}
				}
			}
			
			// 将普通属性排序
			Field[] fis = new Field[fs.size()];
			for (int i = 0; i < fs.size(); i ++) {
				fis[i] = fs.get(i);
			}
			// 按照注解order排序Excel列
			Arrays.sort(fis, new ExcelFieldComparator());
			
			
			for (int i = 0; i < fis.length; i ++) {
                Field field = fis[i];
                if (field.isAnnotationPresent(ExcelField.class)) {
                    //获取该字段的注解对象
                	ExcelField anno = field.getAnnotation(ExcelField.class);
                    sheet.setColumnView(i, anno.width());
                    sheet.addCell(new Label(i, 0, anno.name(), wcf_title));
                }
            }
			
			// 对象中没有出现的字段，并且要在标题中显示的。用于处理对象中的list属性
			if (null != listTitle && listTitle.size() > 0) {
				int len = listTitle.size();
				for (int i = 0; i < len; i ++) {
					sheet.setColumnView(fis.length + i, listTitleWidth.get(i));
					sheet.addCell(new Label(fis.length + i, 0, listTitle.get(i), wcf_title));
				}
			}

			// 写入第几行 第一行为列头 数据从第二行开始写
			int rowId = 1;
			
			for (Object ssTopModel : rows) {
				// 写入第几列 第一列为自动计算的行号 数据从第二列开始写
				int columnId = 0;
				
				// 获取该类 并获取自身方法
				Class clazz = ssTopModel.getClass();
				for (int i = 0; i < fis.length; i ++) {
					Field field = fis[i];
					if (field.isAnnotationPresent(ExcelField.class)) {
						String methodName = "get"
								+ field.getName().substring(0, 1).toUpperCase()
								+ field.getName().substring(1);
						Method method = clazz.getMethod(methodName);
						try {
							sheet.addCell(new Label(columnId, rowId, 
									method.invoke(ssTopModel) == null ? "" : method.invoke(ssTopModel).toString(), wcf_center));
							
							
						} catch (IllegalArgumentException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InvocationTargetException e) {
							e.printStackTrace();
						}
						columnId ++;
					} else {
						System.out.println(field);
					}
				}
				
				
				// 将List属性写入excel
				if (null != listF) {
					Method method = clazz.getMethod("getList");
					List<Object> list = null;
					try {
						list = (List<Object>)method.invoke(ssTopModel);
					} catch (Exception e) {
						e.printStackTrace();
					} 
					if (null != list) {
						for (int i = 0; i < list.size(); i ++) {
							if (list.get(i) != null) {
								if (FIELD_STRING.equals(list.get(i).getClass().getName())) {
									sheet.addCell(new Label(fis.length + i, rowId, 
											list.get(i) == null ? "" : list.get(i).toString(), wcf_center));
								} else {
									Class listClasVo = Class.forName(list.get(i).getClass().getName());
									Field[] listFields = listClasVo.getDeclaredFields();
									List<Field> listFs = new ArrayList<Field>();
									// 获取含有excel注解的属性
									for (Field f : listFields) {
										if (f.getAnnotation(ExcelField.class) != null)
											listFs.add(f);
									}
									
									// 将普通属性排序
									Field[] listFis = new Field[listFs.size()];
									for (int j = 0; j < listFs.size(); j ++) {
										listFis[j] = listFs.get(j);
									}
									// 按照注解order排序Excel列
									Arrays.sort(listFis, new ExcelFieldComparator());
									
									
									for (int x = 0; x < listFis.length; x ++) {
										Field field = listFis[x];
										if (field.isAnnotationPresent(ExcelField.class)) {
											// 处理对象中的List属性
											
											String methodName = "get"
													+ field.getName().substring(0, 1).toUpperCase()
													+ field.getName().substring(1);
											Method fieldMethod = listClasVo.getMethod(methodName);
											try {
												sheet.addCell(new Label(fis.length + (i * listFis.length) + x, rowId, 
														fieldMethod.invoke(list.get(i)) == null ? "" : fieldMethod.invoke(list.get(i)).toString(), wcf_center));
											} catch (Exception ex) {
												ex.printStackTrace();
											}
											columnId++;
										} else {
											System.out.println(field);
										}
									}
								}
							}
						}
					}
				}
				rowId++;
			}

			workbook.write();
			workbook.close();
			os.flush();
			os.close();
		} catch (WriteException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
	}
}
